package top.codecrab.javase;

import java.util.concurrent.TimeUnit;

/**
 * 单例模式，两大种：饿汉式、懒汉式
 * 饿汉式：线程安全
 * 懒汉式：线程不安全（可以调整为安全）
 *
 * @author codecrab
 * @since 2021年06月26日 9:08
 */
@SuppressWarnings("all")
public class Singleton {

    /**
     * 饿汉式
     */
    public static class Hungry {

        /**
         * 饿汉式1：直接new一个实例
         */
        public static class Hungry1 {

            public static final Hungry1 INSTANCE = new Hungry1();

            /**
             * 构造器私有化，防止外部调用，破坏单一性
             */
            private Hungry1() {

            }
        }

        /**
         * 饿汉式2：枚举方式，和第一种一样，胜在简洁，枚举默认构造器私有，线程安全
         */
        public enum Hungry2 {
            INSTANCE
        }

        /**
         * 饿汉式3：静态代码块，可以在代码块中实现业务逻辑
         * 由于类创建时会把静态代码块和静态实例变量一起放在 clinit方法执行，所以也是线程安全的
         */
        public static class Hungry3 {

            private Hungry3() {

            }

            public static final Hungry3 INSTANCE;

            static {
                //System.out.println("可以实现业务逻辑");
                INSTANCE = new Hungry3();
            }
        }
    }

    /**
     * 懒汉式
     */
    public static class Lazy {

        /**
         * 懒汉式1：对外开放一个get方法，获取单例对象
         * 线程不安全
         */
        public static class Lazy1 {

            private Lazy1() {

            }

            private static Lazy1 instance;

            public static Lazy1 getInstance() {
                if (instance == null) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new Lazy1();
                }
                return instance;
            }
        }

        /**
         * 懒汉式2：对外开放一个get方法，使用同步代码块包裹，获取单例对象
         * 线程安全
         */
        public static class Lazy2 {

            private Lazy2() {

            }

            private static Lazy2 instance;

            public static Lazy2 getInstance() {
                synchronized (Lazy2.class) {
                    if (instance == null) {
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        instance = new Lazy2();
                    }
                }
                return instance;
            }
        }

        /**
         * 懒汉式3：懒汉式2优化,在同步代码块外再加一个判断，那么同步代码块执行的次数就会大大减少
         * 线程安全
         */
        public static class Lazy3 {

            private Lazy3() {

            }

            private static Lazy3 instance;

            public static Lazy3 getInstance() {
                //在同步代码块外再加一个判断，那么同步代码块执行的次数就会大大减少
                if (instance == null) {
                    synchronized (Lazy3.class) {
                        if (instance == null) {
                            try {
                                TimeUnit.SECONDS.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            instance = new Lazy3();
                        }
                    }
                }
                return instance;
            }
        }

        /**
         * 懒汉式4：单例对象放在静态内部类，随着类的创建而创建，推荐
         * 线程安全
         */
        public static class Lazy4 {

            private Lazy4() {

            }

            public static Lazy4 getInstance() {
                return Inner.INSTANCE;
            }

            /**
             * 静态内部类是类被调用的时候才初始化，此时INSTANCE才被创建，使用的是ClassLoader，所以是线程安全的
             */
            private static class Inner {

                private static final Lazy4 INSTANCE;

                static {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Lazy4();
                }
            }
        }
    }
}
